<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="zh-cn">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>Listener 监听器 - Jim Li - 博客园</title>
<link type="text/css" rel="stylesheet" href="/bundles/blog-common.css?v=5bITb1XmtieJKhNy3HCsng1mgkC1fjWAtqCxIQA888c1"/>
<link id="MainCss" type="text/css" rel="stylesheet" href="http://common.cnblogs.com/Skins/SimpleBlue/style.css?id=20131027"/>
<link type="text/css" rel="stylesheet" href="/blog/customcss/134424.css?v=99pKNSt%2f%2fb1k00cpoO9YJ2yJT8g%3d"/>
<link title="RSS" type="application/rss+xml" rel="alternate" href="http://www.cnblogs.com/hellojava/rss"/>
<link title="RSD" type="application/rsd+xml" rel="EditURI" href="http://www.cnblogs.com/hellojava/rsd.xml"/>
<link type="application/wlwmanifest+xml" rel="wlwmanifest" href="http://www.cnblogs.com/hellojava/wlwmanifest.xml"/>
<script src="http://common.cnblogs.com/script/jquery.js" type="text/javascript"></script>  
<script type="text/javascript">var currentBlogApp = 'hellojava';</script>
<script src="/bundles/blog-common.js?v=T6Oc14lZG9JOkS67b_zm3VOW-dQWdhBri2GI6Au5mCo1" type="text/javascript"></script>
</head>
<body>
<a name="top"></a>

<div id="home">
<div id="header">
	<div id="blogTitle">
		
<!--done-->
<div class="title"><a id="Header1_HeaderTitle" class="headermaintitle" href="http://www.cnblogs.com/hellojava/">Jim Li</a></div>
<div class="subtitle">思考、总结、原创。每天进步一点点……</div>



		
	</div><!--end: blogTitle 博客的标题和副标题 -->
	<div id="navigator">
		
<ul id="navList">
<li id="nav_sitehome"></li>
<li id="nav_myhome"><a id="MyLinks1_MyHomeLink" class="menu" href="http://www.cnblogs.com/hellojava/">首页</a></li>
<li id="nav_q"><a class="menu" href="http://q.cnblogs.com/">博问</a></li>
<li id="nav_ing"><a class="menu" href="http://home.cnblogs.com/ing/">闪存</a></li>
<li id="nav_newpost"></li>
<li id="nav_contact"><a id="MyLinks1_ContactLink" class="menu" rel="nofollow" href="http://space.cnblogs.com/msg/send/Jim+Li">联系</a></li>
<li id="nav_rss"><a id="MyLinks1_Syndication" class="menu" href="http://www.cnblogs.com/hellojava/rss">订阅</a>
<!--<a id="MyLinks1_XMLLink" class="aHeaderXML" href="http://www.cnblogs.com/hellojava/rss"><img src="http://www.cnblogs.com/images/xml.gif" alt="订阅" /></a>--></li>
<li id="nav_admin"><a id="MyLinks1_Admin" class="menu" rel="nofollow" href="http://www.cnblogs.com/hellojava/admin/EditPosts.aspx">管理</a></li>
</ul>

		<div class="blogStats">
			
			
<!--done-->
随笔-25&nbsp;
文章-0&nbsp;
评论-81&nbsp;

			
		</div><!--end: blogStats -->
	</div><!--end: navigator 博客导航栏 -->
</div><!--end: header 头部 -->
<div id="main">
	<div id="mainContent">
	<div class="forFlow">
		

<!--done-->
<div id="topics">
	<div class = "post">
		<h1 class = "postTitle">
			<a id="cb_post_title_url" class="postTitle2" href="http://www.cnblogs.com/hellojava/archive/2012/12/26/2833840.html">Listener 监听器</a>
		</h1>
		<div class="clear"></div>
		<div class="postBody">
			<div id="cnblogs_post_body"><p>&nbsp;</p>
<p style="text-align: center;"><span style="font-size: 18pt;"><strong><span style="font-family: 宋体;">Listener 监听器</span></strong></span></p>
<p>&nbsp;</p>
<p><span style="font-family: 宋体;">　　前言：之前写了一篇关于Filter的文章：<a href="http://www.cnblogs.com/hellojava/archive/2012/12/19/2824444.html">http://www.cnblogs.com/hellojava/archive/2012/12/19/2824444.html</a>，现在再来一篇Listener的，Filter和Listener在项目中是经常用到的，巧妙的使用可以达到事半功倍的效果。故把两者的用法总结一下。</span></p>
<p><span style="font-size: 14pt;"><strong><span style="font-family: 宋体;">1、Listener的定义与作用</span></strong></span></p>
<p><span style="font-family: 宋体;">　　监听器Listener就是在application,session,request三个对象创建、销毁或者往其中添加修改删除属性时自动执行代码的功能组件。</span></p>
<p><span style="font-family: 宋体;">　　Listener是Servlet的监听器，可以监听客户端的请求，服务端的操作等。</span></p>
<p><span style="font-size: 14pt;"><strong><span style="font-family: 宋体;">2、Listener的分类与使用</span></strong></span></p>
<p><span style="font-family: 宋体;">　　主要有以下三类：</span></p>
<p><span style="font-family: 宋体;">　　<strong>1、ServletContext监听</strong></span></p>
<p><span style="font-family: 宋体;">　　ServletContextListener：用于对Servlet整个上下文进行监听（创建、销毁）。</span></p>
<div class="cnblogs_code">
<pre><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> contextInitialized(ServletContextEvent sce);<span style="color: #008000;">//</span><span style="color: #008000;">上下文初始化</span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> contextDestroyed(ServletContextEvent sce);<span style="color: #008000;">//</span><span style="color: #008000;">上下文销毁</span>

<span style="color: #0000ff;">public</span> ServletContext getServletContext();<span style="color: #008000;">//</span><span style="color: #008000;">ServletContextEvent事件：取得一个ServletContext（application）对象</span></pre>
</div>
<p><span style="font-family: 宋体;">　　ServletContextAttributeListener：对Servlet上下文属性的监听（增删改属性）。</span></p>
<div class="cnblogs_code">
<pre><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> attributeAdded(ServletContextAttributeEvent scab);<span style="color: #008000;">//</span><span style="color: #008000;">增加属性</span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> attributeRemoved(ServletContextAttributeEvent scab);<span style="color: #008000;">//</span><span style="color: #008000;">属性删除</span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> attributeRepalced(ServletContextAttributeEvent scab);<span style="color: #008000;">//</span><span style="color: #008000;">属性替换（第二次设置同一属性）

</span><span style="color: #008000;">//</span><span style="color: #008000;">ServletContextAttributeEvent事件：能取得设置属性的名称与内容</span>
<span style="color: #0000ff;">public</span> String getName();<span style="color: #008000;">//</span><span style="color: #008000;">得到属性名称</span>
<span style="color: #0000ff;">public</span> Object getValue();<span style="color: #008000;">//</span><span style="color: #008000;">取得属性的值</span></pre>
</div>
<p><span style="font-family: 宋体;">　　<strong>2、Session监听</strong></span></p>
<p><span style="font-family: 宋体;">　　Session属于http协议下的内容，接口位于javax.servlet.http.*包下。</span></p>
<p><span style="font-family: 宋体;">　　HttpSessionListener接口：对Session的整体状态的监听。</span></p>
<div class="cnblogs_code">
<pre><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> sessionCreated(HttpSessionEvent se);<span style="color: #008000;">//</span><span style="color: #008000;">session创建</span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> sessionDestroyed(HttpSessionEvent se);<span style="color: #008000;">//</span><span style="color: #008000;">session销毁

</span><span style="color: #008000;">//</span><span style="color: #008000;">HttpSessionEvent事件：</span>
<span style="color: #0000ff;">public</span> HttpSession getSession();<span style="color: #008000;">//</span><span style="color: #008000;">取得当前操作的session</span></pre>
</div>
<p><span style="font-family: 宋体;">　　HttpSessionAttributeListener接口：对session的属性监听。</span></p>
<div class="cnblogs_code">
<pre><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> attributeAdded(HttpSessionBindingEvent se);<span style="color: #008000;">//</span><span style="color: #008000;">增加属性</span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> attributeRemoved(HttpSessionBindingEvent se);<span style="color: #008000;">//</span><span style="color: #008000;">删除属性</span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> attributeReplaced(HttpSessionBindingEvent se);<span style="color: #008000;">//</span><span style="color: #008000;">替换属性

</span><span style="color: #008000;">//</span><span style="color: #008000;">HttpSessionBindingEvent事件：</span>
<span style="color: #0000ff;">public</span> String getName();<span style="color: #008000;">//</span><span style="color: #008000;">取得属性的名称</span>
<span style="color: #0000ff;">public</span> Object getValue();<span style="color: #008000;">//</span><span style="color: #008000;">取得属性的值</span>
<span style="color: #0000ff;">public</span> HttpSession getSession();<span style="color: #008000;">//</span><span style="color: #008000;">取得当前的session</span></pre>
</div>
<p><span style="font-family: 宋体;">　　session的销毁有两种情况：</span></p>
<p><span style="font-family: 宋体;">　　1、session超时，web.xml配置：</span></p>
<div class="cnblogs_code">
<pre><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">session-config</span><span style="color: #0000ff;">&gt;</span>
    <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">session-timeout</span><span style="color: #0000ff;">&gt;</span>120<span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">session-timeout</span><span style="color: #0000ff;">&gt;</span><span style="color: #008000;">&lt;!--</span><span style="color: #008000;">session120分钟后超时销毁</span><span style="color: #008000;">--&gt;</span>
<span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">session-config</span><span style="color: #0000ff;">&gt;</span></pre>
</div>
<p><span style="font-family: 宋体;">　　2、手工使session失效</span></p>
<div class="cnblogs_code">
<pre><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> invalidate();<span style="color: #008000;">//</span><span style="color: #008000;">使session失效方法。session.invalidate();</span></pre>
</div>
<p><span style="font-family: 宋体;">　　<strong>3、Request监听</strong></span></p>
<p><span style="font-family: 宋体;">　　ServletRequestListener：用于对Request请求进行监听（创建、销毁）。</span></p>
<div class="cnblogs_code">
<pre><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> requestInitialized(ServletRequestEvent sre);<span style="color: #008000;">//</span><span style="color: #008000;">request初始化</span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> requestDestroyed(ServletRequestEvent sre);<span style="color: #008000;">//</span><span style="color: #008000;">request销毁

</span><span style="color: #008000;">//</span><span style="color: #008000;">ServletRequestEvent事件：</span>
<span style="color: #0000ff;">public</span> ServletRequest getServletRequest();<span style="color: #008000;">//</span><span style="color: #008000;">取得一个ServletRequest对象</span>
<span style="color: #0000ff;">public</span> ServletContext getServletContext();<span style="color: #008000;">//</span><span style="color: #008000;">取得一个ServletContext（application）对象</span></pre>
</div>
<p><span style="font-family: 宋体;"><span data-mce-mark="1"><span data-mce-mark="1">　　ServletRequestAttributeListener</span>：对Request属性的监听（</span><span data-mce-mark="1">增删改属性</span><span data-mce-mark="1">）。</span></span></p>
<div class="cnblogs_code">
<pre><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> attributeAdded(ServletRequestAttributeEvent srae);<span style="color: #008000;">//</span><span style="color: #008000;">增加属性</span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> attributeRemoved(ServletRequestAttributeEvent srae);<span style="color: #008000;">//</span><span style="color: #008000;">属性删除</span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> attributeReplaced(ServletRequestAttributeEvent srae);<span style="color: #008000;">//</span><span style="color: #008000;">属性替换（第二次设置同一属性）

</span><span style="color: #008000;">//</span><span style="color: #008000;">ServletRequestAttributeEvent事件：能取得设置属性的名称与内容</span>
<span style="color: #0000ff;">public</span> String getName();<span style="color: #008000;">//</span><span style="color: #008000;">得到属性名称</span>
<span style="color: #0000ff;">public</span> Object getValue();<span style="color: #008000;">//</span><span style="color: #008000;">取得属性的值</span></pre>
</div>
<p><span style="font-family: 宋体;">　　<strong>4、在web.xml中配置</strong></span></p>
<p><span style="font-family: 宋体;">　　Listener配置信息必须在Filter和Servlet配置之前，Listener的初始化（ServletContentListener初始化）比Servlet和Filter都优先，而销毁比Servlet和Filter都慢。</span></p>
<div class="cnblogs_code">
<pre><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">listener</span><span style="color: #0000ff;">&gt;</span>
    <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">listener-class</span><span style="color: #0000ff;">&gt;</span>com.listener.class<span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">listener-class</span><span style="color: #0000ff;">&gt;</span>
<span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">listener</span><span style="color: #0000ff;">&gt;</span></pre>
</div>
<p><span style="font-size: 14pt;"><strong><span style="font-family: 宋体;">3、Listener应用实例</span></strong></span></p>
<p><span style="font-family: 宋体;">　　<strong>1、利用HttpSessionListener统计最多在线用户人数</strong></span></p>
<div class="cnblogs_code">
<pre><span style="color: #0000ff;">import</span><span style="color: #000000;"> java.text.DateFormat;
</span><span style="color: #0000ff;">import</span><span style="color: #000000;"> java.text.SimpleDateFormat;
</span><span style="color: #0000ff;">import</span><span style="color: #000000;"> java.util.Date;
</span><span style="color: #0000ff;">import</span><span style="color: #000000;"> javax.servlet.ServletContext;
</span><span style="color: #0000ff;">import</span><span style="color: #000000;"> javax.servlet.http.HttpSessionEvent;
</span><span style="color: #0000ff;">import</span><span style="color: #000000;"> javax.servlet.http.HttpSessionListener;

</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span> HttpSessionListenerImpl <span style="color: #0000ff;">implements</span><span style="color: #000000;"> HttpSessionListener {

    </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> sessionCreated(HttpSessionEvent event) {
        ServletContext app </span>=<span style="color: #000000;"> event.getSession().getServletContext();
        </span><span style="color: #0000ff;">int</span> count = Integer.parseInt(app.getAttribute("onLineCount"<span style="color: #000000;">).toString());
        count</span>++<span style="color: #000000;">;
        app.setAttribute(</span>"onLineCount"<span style="color: #000000;">, count);
        </span><span style="color: #0000ff;">int</span> maxOnLineCount = Integer.parseInt(app.getAttribute("maxOnLineCount"<span style="color: #000000;">).toString());
        </span><span style="color: #0000ff;">if</span> (count &gt;<span style="color: #000000;"> maxOnLineCount) {
            </span><span style="color: #008000;">//</span><span style="color: #008000;">记录最多人数是多少</span>
            app.setAttribute("maxOnLineCount"<span style="color: #000000;">, count);
            DateFormat df </span>= <span style="color: #0000ff;">new</span> SimpleDateFormat("yyyy-MM-dd HH:mm:ss"<span style="color: #000000;">);
            </span><span style="color: #008000;">//</span><span style="color: #008000;">记录在那个时刻达到上限</span>
            app.setAttribute("date", df.format(<span style="color: #0000ff;">new</span><span style="color: #000000;"> Date()));
        }
    }
    </span><span style="color: #008000;">//</span><span style="color: #008000;">session注销、超时时候调用，停止tomcat不会调用</span>
    <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> sessionDestroyed(HttpSessionEvent event) {
        ServletContext app </span>=<span style="color: #000000;"> event.getSession().getServletContext();
        </span><span style="color: #0000ff;">int</span> count = Integer.parseInt(app.getAttribute("onLineCount"<span style="color: #000000;">).toString());
        count</span>--<span style="color: #000000;">;
        app.setAttribute(</span>"onLineCount"<span style="color: #000000;">, count);    
        
    }
}</span></pre>
</div>
<p><span style="font-family: 宋体;">　　<strong>2、Spring使用ContextLoaderListener加载ApplicationContext配置信息</strong></span></p>
<p><span style="font-family: 宋体;">　　ContextLoaderListener的作用就是启动Web容器时，自动装配ApplicationContext的配置信息。因为它实现了ServletContextListener这个接口，在web.xml配置这个监听器，启动容器时，就会默认执行它实现的方法。</span></p>
<p><span style="font-family: 宋体;">　　ContextLoaderListener如何查找ApplicationContext.xml的配置位置以及配置多个xml：如果在web.xml中不写任何参数配置信息，默认的路径是"/WEB-INF/applicationContext.xml"，在WEB-INF目录下创建的xml文件的名称必须是applicationContext.xml（在MyEclipse中把xml文件放置在src目录下）。如果是要自定义文件名可以在web.xml里加入contextConfigLocation这个context参数。</span></p>
<div class="cnblogs_code">
<pre><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">context-param</span><span style="color: #0000ff;">&gt;</span>
    <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">param-name</span><span style="color: #0000ff;">&gt;</span>contextConfigLocation<span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">param-name</span><span style="color: #0000ff;">&gt;</span>
    <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">param-value</span><span style="color: #0000ff;">&gt;</span>classpath:spring/applicationContext-*.xml<span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">param-value</span><span style="color: #0000ff;">&gt;</span><span style="color: #008000;">&lt;!--</span><span style="color: #008000;"> 采用的是通配符方式，查找WEB-INF/spring目录下xml文件。如有多个xml文件，以&ldquo;,&rdquo;分隔。 </span><span style="color: #008000;">--&gt;</span>
<span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">context-param</span><span style="color: #0000ff;">&gt;</span>

<span style="color: #0000ff;">&lt;</span><span style="color: #800000;">listener</span><span style="color: #0000ff;">&gt;</span>
    <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">listener-class</span><span style="color: #0000ff;">&gt;</span>org.springframework.web.context.ContextLoaderListener<span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">listener-class</span><span style="color: #0000ff;">&gt;</span>
<span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">listener</span><span style="color: #0000ff;">&gt;</span></pre>
</div>
<p><span style="font-family: 宋体;">　　<strong>3、Spring使用Log4jConfigListener配置Log4j日志</strong></span></p>
<p><span style="font-family: 宋体;">　　Spring使用Log4jConfigListener的好处：</span></p>
<ol>
<li><span style="font-family: 宋体;">动态的改变记录级别和策略，不需要重启Web应用。</span></li>
<li><span style="font-family: 宋体;">把log文件定在 /WEB-INF/logs/ 而不需要写绝对路径。因为系统把web目录的路径压入一个叫webapp.root的系统变量。这样写log文件路径时不用写绝对路径了。</span></li>
<li><span style="font-family: 宋体;">可以把log4j.properties和其他properties一起放在/WEB-INF/ ，而不是Class-Path。</span></li>
<li><span style="font-family: 宋体;">设置log4jRefreshInterval时间，开一条watchdog线程每隔段时间扫描一下配置文件的变化。</span></li>
</ol>
<div class="cnblogs_code">
<pre><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">context-param</span><span style="color: #0000ff;">&gt;</span>
    <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">param-name</span><span style="color: #0000ff;">&gt;</span>webAppRootKey<span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">param-name</span><span style="color: #0000ff;">&gt;</span>
    <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">param-value</span><span style="color: #0000ff;">&gt;</span>project.root<span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">param-value</span><span style="color: #0000ff;">&gt;</span><span style="color: #008000;">&lt;!--</span><span style="color: #008000;"> 用于定位log文件输出位置在web应用根目录下，log4j配置文件中写输出位置：log4j.appender.FILE.File=${project.root}/logs/project.log </span><span style="color: #008000;">--&gt;</span>
<span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">context-param</span><span style="color: #0000ff;">&gt;</span>
<span style="color: #0000ff;">&lt;</span><span style="color: #800000;">context-param</span><span style="color: #0000ff;">&gt;</span>
    <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">param-name</span><span style="color: #0000ff;">&gt;</span>log4jConfigLocation<span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">param-name</span><span style="color: #0000ff;">&gt;</span>
    <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">param-value</span><span style="color: #0000ff;">&gt;</span>classpath:log4j.properties<span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">param-value</span><span style="color: #0000ff;">&gt;</span><span style="color: #008000;">&lt;!--</span><span style="color: #008000;"> 载入log4j配置文件 </span><span style="color: #008000;">--&gt;</span>
<span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">context-param</span><span style="color: #0000ff;">&gt;</span>
<span style="color: #0000ff;">&lt;</span><span style="color: #800000;">context-param</span><span style="color: #0000ff;">&gt;</span>
    <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">param-name</span><span style="color: #0000ff;">&gt;</span>log4jRefreshInterval<span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">param-name</span><span style="color: #0000ff;">&gt;</span>
    <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">param-value</span><span style="color: #0000ff;">&gt;</span>60000<span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">param-value</span><span style="color: #0000ff;">&gt;</span><span style="color: #008000;">&lt;!--</span><span style="color: #008000;">Spring刷新Log4j配置文件的间隔60秒,单位为millisecond</span><span style="color: #008000;">--&gt;</span>
<span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">context-param</span><span style="color: #0000ff;">&gt;</span>

<span style="color: #0000ff;">&lt;</span><span style="color: #800000;">listener</span><span style="color: #0000ff;">&gt;</span>
    <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">listener-class</span><span style="color: #0000ff;">&gt;</span>org.springframework.web.util.Log4jConfigListener<span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">listener-class</span><span style="color: #0000ff;">&gt;</span>
<span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">listener</span><span style="color: #0000ff;">&gt;</span></pre>
</div>
<p><span style="font-family: 宋体;">　　<strong>4、Spring使用IntrospectorCleanupListener清理缓存</strong></span></p>
<p><span style="font-family: 宋体;">　　这个监听器的作用是在web应用关闭时刷新JDK的JavaBeans的Introspector缓存，以确保Web应用程序的类加载器以及其加载的类正确的释放资源。</span></p>
<p><span style="font-family: 宋体;">　　如果JavaBeans的Introspector已被用来分析应用程序类，系统级的Introspector缓存将持有这些类的一个硬引用。因此，这些类和Web应用程序的类加载器在Web应用程序关闭时将不会被垃圾收集器回收！而IntrospectorCleanupListener则会对其进行适当的清理，已使其能够被垃圾收集器回收。</span></p>
<p><span style="font-family: 宋体;">　　唯一能够清理Introspector的方法是刷新整个Introspector缓存，没有其他办法来确切指定应用程序所引用的类。这将删除所有其他应用程序在服务器的缓存的Introspector结果。</span></p>
<p><span style="font-family: 宋体;">　　在使用Spring内部的bean机制时，不需要使用此监听器，因为Spring自己的introspection results cache将会立即刷新被分析过的JavaBeans Introspector cache，而仅仅会在应用程序自己的ClassLoader里面持有一个cache。虽然Spring本身不产生泄漏，注意，即使在Spring框架的类本身驻留在一个&ldquo;共同&rdquo;类加载器（如系统的ClassLoader）的情况下，也仍然应该使用使用IntrospectorCleanupListener。在这种情况下，这个IntrospectorCleanupListener将会妥善清理Spring的introspection cache。</span></p>
<p><span style="font-family: 宋体;">　　应用程序类，几乎不需要直接使用JavaBeans Introspector，所以，通常都不是Introspector resource造成内存泄露。相反，许多库和框架，不清理Introspector，例如： Struts和Quartz。</span></p>
<p><span style="font-family: 宋体;">　　需要注意的是一个简单Introspector泄漏将会导致整个Web应用程序的类加载器不会被回收！这样做的结果，将会是在web应用程序关闭时，该应用程序所有的静态类资源（比如：单实例对象）都没有得到释放。而导致内存泄露的根本原因其实并不是这些未被回收的类！</span></p>
<p><span style="font-family: 宋体;">　　注意：IntrospectorCleanupListener应该注册为web.xml中的第一个Listener，在任何其他Listener之前注册，比如在Spring's ContextLoaderListener注册之前，才能确保IntrospectorCleanupListener在Web应用的生命周期适当时机生效。</span></p>
<div class="cnblogs_code">
<pre><span style="color: #008000;">&lt;!--</span><span style="color: #008000;"> memory clean </span><span style="color: #008000;">--&gt;</span>
<span style="color: #0000ff;">&lt;</span><span style="color: #800000;">listener</span><span style="color: #0000ff;">&gt;</span>
    <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">listener-class</span><span style="color: #0000ff;">&gt;</span>org.springframework.web.util.IntrospectorCleanupListener<span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">listener-class</span><span style="color: #0000ff;">&gt;</span>
<span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">listener</span><span style="color: #0000ff;">&gt;</span></pre>
</div>
<p>&nbsp;</p></div><div id="MySignature"></div>
<div class="clear"></div>
<div id="blog_post_info_block">
<div id="blog_post_info">
</div>
<div class="clear"></div>
<div id="post_next_prev"></div>
</div>


		</div>
		<div class = "postDesc">posted @ <span id="post-date">2012-12-26 13:08</span> <a href='http://www.cnblogs.com/hellojava/'>Jim Li</a> 阅读(<span id="post_view_count">...</span>) 评论(<span id="post_comment_count">...</span>)  <a href ="http://www.cnblogs.com/hellojava/admin/EditPosts.aspx?postid=2833840" rel="nofollow">编辑</a> <a href="#" onclick="AddToWz(2833840);return false;">收藏</a></div>
	</div>
	<script type="text/javascript">var allowComments=true,isLogined=false,cb_blogId=134424,cb_entryId=2833840,cb_blogApp=currentBlogApp,cb_blogUserGuid='7999267f-a033-e211-aa8f-842b2b196315',cb_entryCreatedDate='2012/12/26 13:08:00';loadViewCount(cb_entryId);</script>
	
</div><!--end: topics 文章、评论容器-->
<a name="!comments"></a><div id="blog-comments-placeholder"></div><script type="text/javascript">var commentManager = new blogCommentManager();commentManager.renderComments(0);</script>
<div id="comment_form" class="commentform">
<a name="commentform"></a>
<div id="divCommentShow"></div>
<div id="comment_nav"><span id="span_refresh_tips"></span><a href="javascript:void(0);" id="lnk_RefreshComments" onclick="return RefreshCommentList();">刷新评论</a><a href="#" onclick="return RefreshPage();">刷新页面</a><a href="#top">返回顶部</a></div>
<div id="comment_form_container"></div>
<div class="ad_text_commentbox" id="ad_text_under_commentbox"></div>
<div id="site_nav_under"><a href="http://www.cnblogs.com/" target="_blank" title="程序员的网上家园">博客园首页</a><a href="http://q.cnblogs.com/" target="_blank" title="程序员问答社区">博问</a><a href="http://news.cnblogs.com/" target="_blank" title="IT新闻">新闻</a><a href="http://home.cnblogs.com/ing/" target="_blank">闪存</a><a href="http://job.cnblogs.com/" target="_blank">程序员招聘</a><a href="http://kb.cnblogs.com/" target="_blank">知识库</a></div>
<div id="ad_under_post_holder"></div>
<script type="text/javascript">
var enableGoogleAd = true;
var googletag = googletag || {};
googletag.cmd = googletag.cmd || [];
fixPostBodyFormat();
loadAdUnderPost();
</script>
<div id="HistoryToday" class="c_ad_block"></div>
<script type="text/javascript">
loadBlogSignature();
LoadPostInfoBlock(cb_blogId, cb_entryId, cb_blogApp, cb_blogUserGuid);
GetPrevNextPost(cb_entryId, cb_blogId, cb_entryCreatedDate);
GetHistoryToday(cb_blogId, cb_blogApp, cb_entryCreatedDate);
</script>
<script type="text/javascript">
    $.ajax({ url: 'http://counter.cnblogs.com/blog/post/' + cb_entryId, type: 'get', dataType: 'script', cache: true });
</script>
</div>

	</div><!--end: forFlow -->
	</div><!--end: mainContent 主体内容容器-->

	<div id="sideBar">
		<div id="sideBarMain">
			
<!--done-->
<div class="newsItem">
<h3 class="catListTitle">公告</h3>
	<div id="blog-news"></div><script type="text/javascript">loadBlogNews();</script>
</div>

			<div id="calendar"><div id="blog-calendar" style="displya:none"></div><script type="text/javascript">loadBlogDefaultCalendar();</script></div>
			
			<div id="leftcontentcontainer">
				<div id="blog-sidecolumn"></div><script type="text/javascript">loadBlogSideColumn();</script>
			</div>
			
		</div><!--end: sideBarMain -->
	</div><!--end: sideBar 侧边栏容器 -->
	<div class="clear"></div>
	</div><!--end: main -->
	<div class="clear"></div>
	<div id="footer">
		
<!--done-->
Copyright &copy;2013 Jim Li
	</div><!--end: footer -->
</div><!--end: home 自定义的最大容器 -->
<script type="text/javascript" src="http://common.cnblogs.com/script/google-analytics.js"></script>
</body>
</html>
